package com.csaba.connector.otp;

import java.io.StringReader;
import java.util.logging.Logger;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import com.csaba.connector.I18NServiceException;
import com.csaba.connector.ServiceException;
import com.csaba.connector.model.Account;
import com.csaba.connector.model.Session;
import com.csaba.connector.otp.model.OTPBank;
import com.csaba.connector.otp.model.OTPRequestFactory;
import com.csaba.connector.otp.model.OTPSession;
import com.csaba.connector.otp.parser.AccountBalanceParser;
import com.csaba.connector.otp.parser.AccountHistoryParser;
import com.csaba.connector.otp.parser.OTPCodes;
import com.csaba.connector.service.AbstractAccountService;
import com.csaba.util.LoggerHelper;

/**
 * @author Gabe
 */
public class OTPAccountService extends AbstractAccountService
{
	private final static Logger logger = LoggerHelper.getDefaultLogger();

	private final static String ACCOUNT_SELECTION = "account.selection";

	@Override
	public void execute( final Session session ) throws ServiceException
	{
		if ( !( session instanceof OTPSession ) )
			throw new ServiceException("Unsupported session for OTP services: " + session.getClass().getName());

		final OTPSession otp = (OTPSession) session;

		final Account[] accounts = (Account[]) otp.getRemoteProperty(OTPCodes.RP_ACCOUNT_LIST);

		//get details for each account
		for ( final Account account : accounts )
		{
			if ( account == null || !account.isRemotePropertySet(OTPCodes.RP_ACCOUNT_DETAILS_URL) )
				continue;

			final String detailsUrl = (String) account.getRemoteProperty(OTPCodes.RP_ACCOUNT_DETAILS_URL);

			final String accountDetailsResult = otp.doGet(OTPRequestFactory.HOMEBANK_SERVER_URL + detailsUrl);
			otp.debugFile("accountDetailsResult" + account.getNumber(), accountDetailsResult);

			//poll result
			final String pollUrl = WorkflowPolling.parsePollTransaction(accountDetailsResult);
			if ( pollUrl == null )
			{
				throw new I18NServiceException(OTPBank.getInstance(), "msg.accountDownloadError",
						"Nem megfelelő számlarészlet válasz. Várakozó instrukciók hiányoznak.");
			}

			if ( !( new WorkflowPolling(otp, pollUrl) ).poll() )
			{
				throw new I18NServiceException(OTPBank.getInstance(), "msg.accountTimeout",
						"Számlarészletek nem jöttek le a várakozás után.");
			}

			final NameValuePair[] data = new NameValuePair[] {
					new BasicNameValuePair("kliensTranzakcioId", String.valueOf(otp.getOperationCounter())),
					new BasicNameValuePair("muveletStatusz", "varakozas"), };

			final String accountDetailsResult2 = otp.doPost(OTPRequestFactory.HOMEBANK_REQUEST_URL_BASE
					+ OTPRequestFactory.REQUEST_GET_MAIN_DATA, data);
			otp.debugFile("accountDetails2Reply" + account.getNumber() + ".html", accountDetailsResult2);

			// set received details
			try
			{
				AccountBalanceParser.extractAccountDetails(new StringReader(accountDetailsResult2), account);
			}
			catch ( final Exception e )
			{
				throw new I18NServiceException(OTPBank.getInstance(), "msg.accountProcessingError", e);
			}
		}
	}

	static void selectAccount( final Account account, final OTPSession otp ) throws ServiceException
	{
		//select account if not yet selected
		boolean needToSelect = true;
		try
		{
			final String accountSelect = (String) otp.getRemoteProperty(ACCOUNT_SELECTION);
			needToSelect = !accountSelect.equals(account.getRemoteProperty(AccountBalanceParser.ACCOUNT_INDEX));
		}
		catch ( final Exception ex )
		{
			logger.finer("Remote property is missing: " + ex);
		}

		if ( needToSelect )
		{
			final String accountSelectResult = otp.doGet(OTPRequestFactory.HOMEBANK_REQUEST_URL_BASE
					+ OTPRequestFactory.REQUEST_GET_ACCOUNT_LIST + "?szamlaSzamIndex="
					+ account.getRemoteProperty(AccountBalanceParser.ACCOUNT_INDEX));
			otp.debugFile("accountSelectResult", accountSelectResult);
			if ( AccountHistoryParser.isFailed(accountSelectResult) )
			{
				//no need to parse exception as no useful details are sent by the bank
				throw new I18NServiceException(OTPBank.getInstance(), "msg.accountSelectError", (Throwable) null,
						account);
			}

			otp.setRemoteProperty(ACCOUNT_SELECTION, account.getRemoteProperty(AccountBalanceParser.ACCOUNT_INDEX));
		}

	}
}
